﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using Small.Html.Options;
using Small.Html.Entities;
using Small.Util.Reflection;

namespace Small.Html.UI
{
    public static class HtmlTreeList
    {


        private static List<String> linkFields;
        private static List<String> displayFields;
        private static Int32 displayLevel;
        private static StringBuilder heahBuilder = null;
        private static List<String> headList = null;
        private static List<ExpressItem> tableDisplayFields = null;
        private static Int32 paddingSpace;
        private static string collapseClass;
        private static string tableClass;

        private static string itemClass;

        private static string linkClass;
        /// <summary>
        /// 树形列表
        /// </summary>
        /// <typeparam name="T">泛型T</typeparam>
        /// <param name="helper"></param>
        /// <param name="options"></param>
        /// <param name="htmlAttribute"></param>
        /// <returns></returns>
        public static MvcHtmlString TreeList<T>(this HtmlHelper helper, TreeListOptions<T> options,object htmlAttribute=null) where T : new()
        {

            string htmlString = IntialDataSource<T>(options,htmlAttribute);

            return new MvcHtmlString(htmlString);
        }



        private static string IntialDataSource<T>(TreeListOptions<T> options,object htmlAttribute) where T : new()
        {
            //主键
            var keyFieldName = BaseHelper.GetExpressName<T>(options.Key);
            //父节点
            var parentIdName = BaseHelper.GetExpressName<T>(options.ParentID).Text;
            OrderByList<T>((List<T>)options.List, parentIdName);
            var expandName = BaseHelper.GetExpressName<T>(options.Expand);
            displayLevel = options.Level;
            linkClass = options.LinkClass;
            collapseClass = options.CollapseClass;
            //获取到要显示的名称
            paddingSpace = options.PaddingSpace;
            tableDisplayFields = TableDisplayFields<T>(options);
            displayFields = GetFieldList<T>(options, displayFields);
            itemClass = options.ItemClass;
            tableClass = options.TableClass;
            StringBuilder builder = new StringBuilder();
            ElementBegin<T>(builder, htmlAttribute);
            //超链接集合
            linkFields = GetLinkField<T>(options);
            //循环
                builder.Append(HtmlTableHead<T>());
                TreeList treeList = GetTree<T>(options, builder);
            EelementEnd<T>( builder);
            return builder.ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        private static TreeList GetTree<T>(TreeListOptions<T> options, StringBuilder builder)
        {
            var parentName = BaseHelper.GetExpressName(options.ParentID).Text;
            var keyName = BaseHelper.GetExpressName(options.Key).Text;
            var expandName = BaseHelper.GetExpressName(options.Expand).Text;
            TreeList treeList = new TreeList();
            treeList.Nodes = new List<TreeNode>();
            var parentNode = GetListByCondiction<T>(options.List, parentName);
            foreach (var item in parentNode)
            {
                var keyValue = Convert.ToString(item.GetType().GetProperty(keyName).GetValue(item));
                TreeNode node = new TreeNode();
                node.Content = new TreeItem
                {
                    Key = keyName,
                    Parent = parentName,
                    PaddingLeft = options.PaddingLeft,
                    Expand = expandName,
                    Value = keyValue,
                    ItemClass = options.ExpandClass,
                    DispalyLevel = 0
                };
                node.ChildNodes = new List<TreeNode>();
                var nodes = GetListByCondiction<T>(options.List, parentName, node.Content.Value);
                if (nodes.Count() > 0)
                {
                    node.HasChild = true;
                }
                builder.Append(HtmlTableRow<T>(node.Content, item, node.Content.PaddingLeft, node.HasChild));
                GetNodeList(options.List, node, keyName, parentName, expandName, builder);
                treeList.Nodes.Add(node);
            }
            return treeList;
        }

        /// <summary>
        /// 获取到父节点
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="parentName"></param>
        /// <returns></returns>
        private static IEnumerable<T> GetListByCondiction<T>(IList<T> list, string parentName, string value = null)
        {
            List<T> resultList = new List<T>();
            foreach (var item in list)
            {
                T t = item;
                var parentId = Convert.ToString(t.GetType().GetProperty(parentName).GetValue(t));
                if (String.IsNullOrEmpty(value))
                {
                    parentId = parentId.Replace("0", "");
                    if (!String.IsNullOrEmpty(parentId))
                    {
                        continue;
                    }
                }
                else
                {
                    if (parentId != value)
                    {
                        continue;
                    }
                }
                resultList.Add(item);
            }
            return resultList;
        }
        /// <summary>
        /// 获取到节点
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="node"></param>
        /// <param name="keyName"></param>
        /// <param name="parentName"></param>
        /// <param name="expandName"></param>
        /// <param name="builder"></param>
        private static void GetNodeList<T>(IList<T> list, TreeNode node, string keyName, string parentName, string expandName, StringBuilder builder)
        {
            var nodes = GetListByCondiction<T>(list, parentName, node.Content.Value);
            //list.Where(p => Convert.ToString(p.ParentID).Equals(node.Content.Key));
            foreach (var item2 in nodes)
            {
                var keyValue = Convert.ToString(item2.GetType().GetProperty(keyName).GetValue(item2));
                TreeNode node2 = new TreeNode();
                node2.Content = new TreeItem
                {
                    Key = keyName,
                    Parent = parentName,
                    PaddingLeft = node.Content.PaddingLeft + paddingSpace,
                    Expand = expandName,
                    Value = keyValue,
                    ItemClass = node.Content.ItemClass,
                    DispalyLevel = node.Content.DispalyLevel + 1
                };
                if (node.ChildNodes == null)
                {
                    node.ChildNodes = new List<TreeNode>();
                }
                var nodes3 = GetListByCondiction<T>(list, parentName, keyValue);
                if (nodes3.Count() > 0) { node2.HasChild = true; }
                //= list.Where(p => Convert.ToString(p.ParentID).Equals(node2.Content.Key));
                builder.Append(HtmlTableRow<T>(node2.Content, item2, node2.Content.PaddingLeft, node2.HasChild));
                if (nodes3.Count() > 0)
                {
                    GetNodeList(list, node2, keyName, parentName, expandName, builder);
                }
                node.ChildNodes.Add(node2);

            }
        }

    

        /// <summary>
        /// 初始化标题
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private static string HtmlTableHead<T>()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("<tr>");
            foreach (var item in tableDisplayFields)
            {
                builder.Append(String.Format("<td align=\"center\">{0}</td>", item.Value));
            }
            builder.Append("</tr>" + Environment.NewLine);
            return builder.ToString();
        }


        /// <summary>
        /// 获取到要显示的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="options"></param>
        /// <returns></returns>
        private static List<ExpressItem> TableDisplayFields<T>(TreeListOptions<T> options) where T : new()
        {
            List<ExpressItem> list = new List<ExpressItem>();
            if (options.Fields == null)
            {
                var expand = BaseHelper.GetExpressName<T>(options.Expand);
                var key = BaseHelper.GetExpressName<T>(options.Key).Text;
                var parent = BaseHelper.GetExpressName<T>(options.ParentID).Text;
                if (options.Fields == null)
                {
                    T t = new T();
                    List<string> list1 = DefinationProperties.GetName<T>(t);
                    ExpressItem item1 = new ExpressItem { Text = expand.Text, Value = expand.Value };
                    list.Add(item1);
                    list1.Remove(key);
                    list1.Remove(expand.Text);
                    list1.Remove(parent);
                    foreach (var item in list1)
                    {
                        ExpressItem item2 = new ExpressItem { Text = item, Value = item };
                        list.Add(item2);

                    }
                }
            }
            else
            {

                ExpressItem item1 = BaseHelper.GetExpressName<T>(options.Expand);
                list.Add(item1);
                foreach (var item in options.Fields)
                {
                    var name=BaseHelper.GetExpressName<T>(item);
                    if (name.Text != item1.Text)
                    {
                        list.Add(name);
                    }
                }
            }

            return list;
        }



        private static string HtmlTableRow<T>(TreeItem itemOptions, T t, int padding_left, bool hasChild)
        {
            StringBuilder builder = new StringBuilder();

            Dictionary<String, String> tInfo = DefinationProperties.GetProperties<T>(t);

            if (itemOptions.DispalyLevel >= displayLevel)
            {
                builder.

          Append(String.Format("<tr data-key=\"{0}\" data-parentkey=\"{1}\" style=\"display:none;\">" + Environment.NewLine, tInfo[itemOptions.Key], tInfo[itemOptions.Parent]));
            }
            else
            {
                builder.

       Append(String.Format("<tr data-key=\"{0}\" data-parentkey=\"{1}\">" + Environment.NewLine, tInfo[itemOptions.Key], tInfo[itemOptions.Parent]));
            }
            tInfo.Remove(itemOptions.Key);
            tInfo.Remove(itemOptions.Parent);


            foreach (var item in tableDisplayFields)
            {

                    builder.Append("<td".PadLeft(padding_left));
                
                if (item.Text.Equals(itemOptions.Expand)) 
                {

                    builder.Append(String.Format(" style=\"padding-left:{0}px; padding-right:10px;\" ", padding_left));
                }
                builder.Append(">");
                if (hasChild && item.Text.Equals(itemOptions.Expand))
                {

                    if (itemOptions.DispalyLevel < (displayLevel-1))
                    {
                        builder.Append(String.Format("<span class=\"{0}\" ></span>", itemOptions.ItemClass));
                    }
                    else 
                    {
                        builder.Append(String.Format("<span class=\"{0}\" ></span>", collapseClass));
                 
                    }
                }
                else if (!hasChild && item.Text.Equals(itemOptions.Expand)) 
                {
                    builder.Append(String.Format("<span class=\"{0}\" ></span>", itemClass));
                }
                if (linkFields.Contains(item.Text))
                {

                    builder.Append(String.Format("<a href=\"javascript:void(0);\" class=\"{0}\" data-name=\"{1}\" >{2}</a>",
                    linkClass, item.Text, String.IsNullOrEmpty(tInfo[item.Text]) ? "&nbsp" : tInfo[item.Text]));

                }
                else
                {
                    builder.Append(String.Format("{0}", String.IsNullOrEmpty(tInfo[item.Text]) ? "&nbsp" : tInfo[item.Text]));
                }

                builder.Append("</td>" + Environment.NewLine);

            }
            builder.Append("    </tr>" + Environment.NewLine);
            return builder.ToString();
        }
        //获取到要遍历的List
        private static List<T> GetList<T>(List<T> sourceList, string keyName, string parentName, string parentValue)
        {
            List<T> list = new List<T>();
            if (sourceList == null) { return list; }
            int sourceListIndex = 0;
            while (sourceList.Count < (sourceListIndex - 1))
            {
                T t = sourceList[sourceListIndex];
                var keyValue = Convert.ToString(t.GetType().GetProperty(keyName).GetValue(t));
                if (parentValue.Equals(keyValue))
                {
                    var newParentValue = Convert.ToString(t.GetType().GetProperty(parentName).GetValue(t));
                    list.Add(t);
                    list.Remove(t);
                    sourceListIndex--;
                    if (list.Count > 0)
                    {

                        GetList<T>(list, keyName, parentName, newParentValue);
                    }
                }
                sourceListIndex++;
            }
            return list;
        }

        private static void EelementEnd<T>( StringBuilder builder) where T : new()
        {
          
                builder.Append("</table>" + Environment.NewLine);
           
        }

        private static void ElementBegin<T>( StringBuilder builder,object htmlAttributes) where T : new()
        {

            builder.Append(String.Format("<table class=\"{0}\"  cellpadding=\"0\"  cellspacing=\"0\" {1}>", tableClass, builder.Append(BaseHelper.FormatGenerateAttribute(htmlAttributes))));
           
        }
        //获取到要显示字段名称
        private static List<string> GetFieldList<T>(TreeListOptions<T> options, List<String> fields) where T : new()
        {

            var expand = BaseHelper.GetExpressName<T>(options.Expand).Text;
            var key = BaseHelper.GetExpressName<T>(options.Key).Text;
            var parent = BaseHelper.GetExpressName<T>(options.ParentID).Text;
            if (options.Fields == null)
            {
                T t = new T();
                fields = DefinationProperties.GetName<T>(t);
            }
            else
            {
                fields = BaseHelper.GetDisplayFields<T>(options.Fields.ToList());
            }
            fields.Remove(key);
            fields.Remove(parent);
            fields.Remove(expand);
            fields.Insert(0, expand);
            return fields;
        }

        public static List<String> GetLinkField<T>(TreeListOptions<T> options) where T : new()
        {
            List<String> list = new List<string>();
            if (options.LinkFields != null)
            {

                foreach (var item in options.LinkFields)
                {
                    list.Add(BaseHelper.GetExpressName<T>(item).Text);

                }
            }
            return list;

        }
        //对源数据进行排序
        private static void OrderByList<T>(List<T> list, string parentName)
        {
            List<T> list1 = new List<T>();
            List<T> list2 = new List<T>();

            foreach (var item in list)
            {
                var parentValue = Convert.ToString(item.GetType().GetProperty(parentName).GetValue(item));
                if (String.IsNullOrEmpty(parentValue) || parentValue == "0")
                {
                    list1.Add(item);
                }
                else
                {
                    list2.Add(item);
                }
            }
            list.Clear();
            list.AddRange(list1);
            list.AddRange(list2);
        }

    }
}
